#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <cassert>

const int getcap = 5;
template <class T>
class ring_queue
{
private:
    // P操作主要是对数据量进行预定
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);
        (void)n;
    }
    //主要是对信号量进行还原
    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }
public:
    ring_queue(const int cap = getcap) : _queue(cap), _cap(cap)
    {
        // 初始化信号量
        int n = sem_init(&_productor_sem, 0, _cap); // 初始化信号量,注意这里对生产者数量的初始化时剩余的可以放置任务线程的个数
        assert(n == 0);
        (void)n;
        n = sem_init(&_comsumer_sem, 0, 0);       //初始化消费者生产量，注意这里是对消费者可以消费的数量进行初始化，初始应该为0
        assert(n == 0);
        (void)n;
        //对消费者和生产者的位置进行初始化
        _spacePostion = _dataPostion = 0;

        //对锁进行初始化，这里需要两把锁，对于 生产者和消费者而言，他们是互斥的
        pthread_mutex_init(&_productor_mutex,nullptr);
        pthread_mutex_init(&_comsumer_mutex,nullptr);

    }
    void Push(const T &in)
    {
        // 主要是进行PV操作，首先需要明确的是PV操作是原子性的
        //首先对资源进行预定
        P(_productor_sem);
        
        //对这里进行加锁的时候需要注意，在P操作之后加锁，在V操作之前解锁
        //因为PV操作是原子性的，所以可以不用加锁，而且加锁的话会影响其余线程提前对资源的预定，浪费时间
        //如果在P操作之前加锁，那么必须等这个线程在释放锁之后，其余线程才能申请资源在进行后续操作 ，比较浪费时间
        //生产者消费者模型节约时间主要是在 在该生产者线程进行操作的时候，其余线程可以先去预定资源，申请任务，以及后续的在任务执行完成之后，并行完成后续的一系列操作
        pthread_mutex_lock(&_productor_mutex);
        _queue[_spacePostion++]=in;
        _spacePostion%=_cap;
        pthread_mutex_unlock(&_productor_mutex);

        V(_comsumer_sem); //消费者可以消费的资源+1

    }
    void Pop(T *out)
    {
        //主要是对消费者进行PV操作，首先需要注意的是这里需要对消费者P操作，生产者V操作
        //首先消费者对资源进行消费预定
        P(_comsumer_sem);
        pthread_mutex_lock(&_comsumer_mutex);
        *out = _queue[_dataPostion++];
        _dataPostion%=_cap;
        pthread_mutex_unlock(&_comsumer_mutex);
        V(_productor_sem); //生产者可以生产的资源+1
    }
    ~ring_queue()
    {
        // 销毁信号量
        sem_destroy(&_productor_sem);
        sem_destroy(&_comsumer_sem);
        //对锁进行销毁
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_comsumer_mutex);

    }

private:
    std::vector<T> _queue;
    int _cap;
    sem_t _productor_sem;
    sem_t _comsumer_sem;
    int _spacePostion;
    int _dataPostion;
    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _comsumer_mutex;

};